package ru.spbu.math.android.cbrf.dataprovider.yandex;

import android.content.res.Resources;
import android.util.Log;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import ru.spbu.math.android.cbrf.R;
import ru.spbu.math.android.cbrf.dataprovider.IProvider;
import ru.spbu.math.android.cbrf.dataprovider.UnavailableValueException;
import ru.spbu.math.android.cbrf.model.Category;
import ru.spbu.math.android.cbrf.model.Rate;
import ru.spbu.math.android.cbrf.model.RateType;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Class for getting data from Yandex This class implements IProvider
 */

public class YandexProvider implements IProvider {

	private static final String TAG = "Yandex Provider";

	private static final String URL = "http://news.yandex.ru/quotes/";
	private static final String URL_DINAM = "http://news.yandex.ru/quotes/graph_";

	private Resources resources;

	public YandexProvider(Resources res) {
		resources = res;
		RateTypeStore.Instance(res);
	}

	/**
	 * Check connection with Yandex
	 * 
	 * @return
	 */
	public boolean isUpdatableNow() {
		try {
			URL url = new URL(URL);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.connect();
			Log.d(TAG, "Is Updatable");
			return true;
		} catch (IOException e) {
			Log.e(TAG, "Isn't update now");
			return false;
		}
	}

	private List<Rate> getListYandexData(String id) {

		RateTypeStore instance = RateTypeStore.Instance(resources);
		try {
			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser parser = factory.newSAXParser();

			URL url = new URL(URL + id + ".xml");
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			InputSource courseXml = new InputSource(new InputStreamReader(
					conn.getInputStream(), "utf-8"));
			YandexSaxHandler handler = new YandexSaxHandler();
			handler.setRate(instance.findRateTypeById(id));
			parser.parse(courseXml, handler);
			List<Rate> itemList = handler.getRateItem();
			Log.d(TAG, "Get List Yandex Data");
			return itemList;

		} catch (MalformedURLException e) {
			Log.e(TAG, "MalformedURLException");
		} catch (IOException e) {
			Log.e(TAG, "IOException");
		} catch (SAXException e) {
			Log.e(TAG, "SAXException");
		} catch (ParserConfigurationException e) {
			Log.e(TAG, "ParserConfigurationException");
		}

		return null;
	}

	private List<Rate> getDynamicYandexData(String id, Date since, Date until) {
		try {
			SAXParserFactory factory = SAXParserFactory.newInstance();
			SAXParser parser = factory.newSAXParser();

			URL url = new URL(URL_DINAM + id + ".xml");
			URLConnection conn = url.openConnection();

			long dateStart = since.getTime();
			long dateFinish = until.getTime();

			InputSource courseXml = new InputSource(new InputStreamReader(
					conn.getInputStream(), "utf-8"));
			YandexDynamicSaxHandler handler = new YandexDynamicSaxHandler();
			parser.parse(courseXml, handler);
			List<Rate> itemList = handler.getRateItem(dateStart, dateFinish);
			return itemList;

		} catch (MalformedURLException e) {
			Log.e(TAG, "MalformedURLException");
		} catch (IOException e) {
			Log.e(TAG, "IOException");
		} catch (SAXException e) {
			Log.e(TAG, "SAXException");
		} catch (ParserConfigurationException e) {
			Log.e(TAG, "ParserConfigurationException");
		}

		return null;
	}

	@Override
	public Rate getCurrentRate(String id) throws UnavailableValueException {
		if (!isUpdatableNow())
			throw new UnavailableValueException();

		Log.d(TAG, "Get Latest Rate");
		List<Rate> rateList = new ArrayList<Rate>();
		rateList = getListYandexData(id);

		if (rateList == null)
			throw new UnavailableValueException();

		if (rateList.get(0) == null) {
			throw new UnavailableValueException();
		}

		if ((rateList.size() > 1) && (rateList.get(1) != null)) {
			Rate rate = rateList.get(0);
			rate.setDifference(rate.getValue() - rateList.get(1).getValue());
		}
		return rateList.get(0);
	}

	@Override
	public List<Rate> getDynamicRates(String id, Date since, Date until)
			throws UnavailableValueException {
		RateTypeStore instance = RateTypeStore.Instance(resources);
		RateType rateType = instance.findRateTypeById(id);
		if (!isUpdatableNow())
			throw new UnavailableValueException();
		if (!rateType.getTarget().getCode().equals("USD"))
			throw new UnavailableValueException();

		List<Rate> rateList = new ArrayList<Rate>();
		rateList = getDynamicYandexData(id, since, until);

		if ((rateList == null) || (rateList.size() == 0)) {
			throw new UnavailableValueException();
		}
		return rateList;
	}

	@Override
	public List<Category> getCategories() {
		RateTypeStore instance = RateTypeStore.Instance(resources);
		return instance.getCategories();
	}

	@Override
	public List<RateType> getRateTypeByCategory(Category category) {
		RateTypeStore instance = RateTypeStore.Instance(resources);
		return instance.getRateTypesByCategory(category);
	}

	@Override
	public String getName() {
		return resources.getString(R.string.Yandex_Name);
	}
}
